package com.reborn.mall.api.service.impl;

import com.google.common.collect.Lists;
import com.reborn.mall.api.common.util.BeanUtil;
import com.reborn.mall.api.common.util.DateUtil;
import com.reborn.mall.api.model.dto.OrderDTO;
import com.reborn.mall.api.model.entity.CartItem;
import com.reborn.mall.api.model.entity.Order;
import com.reborn.mall.api.model.entity.OrderItem;
import com.reborn.mall.api.model.entity.OrderOperateHistory;
import com.reborn.mall.api.model.vo.OrderVO;
import com.reborn.mall.api.mybatis.mapper.OrderMapper;
import com.reborn.mall.api.service.CartItemService;
import com.reborn.mall.api.service.OrderItemService;
import com.reborn.mall.api.service.OrderOperateHistoryService;
import com.reborn.mall.api.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * TODO: Here is description
 *
 * @author wu.yue
 * @since 2020/3/12
 */
@Service
public class OrderServiceImpl extends BaseServiceImpl<Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private CartItemService cartItemService;

    @Autowired
    private OrderOperateHistoryService orderOperateHistoryService;

    @Override
    public String generateUniqueOrderNumber() {
        int machineId = 1;//最大支持1-9个集群机器部署
        int hashCodeV = UUID.randomUUID().toString().hashCode();
        if(hashCodeV < 0) {//有可能是负数
            hashCodeV = - hashCodeV;
        }
        // 0 代表前面补充0
        // 4 代表长度为4
        // d 代表参数为正数型
        return machineId + String.format("%015d", hashCodeV);
    }

    @Override
    @Transactional
    public Order createOrder(OrderDTO orderDTO) {
        // insert to order table
        Order order = insertOrderData(orderDTO);

        // clear user cart items
        List<CartItem> cartItems = removeCartItemsOfThisOrder(orderDTO);

        // insert to order item table
        insertOrderItemData(order, cartItems);

        // insert to order history table
        insertOrderOperateHistoryData(order, order.getCreateTime());
        return order;
    }

    @Override
    public List<OrderVO> findOrdersByAppUserId(Long appUserId) {
        // first, find orders by appUserId
        Order order = new Order();
        order.setAppUserId(appUserId);
        List<Order> orders = find(order);

        // then, transform each order to orderVO and set orderItems for each orderVO
        List<OrderVO> orderVOs = Lists.newArrayList();
        for (Order o : orders) {
            OrderVO orderVO = BeanUtil.copyProperties(o, OrderVO.class);
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderId(o.getId());
            List<OrderItem> orderItems = orderItemService.find(orderItem);
            orderVO.setOrderItems(orderItems);
            orderVOs.add(orderVO);
        }
        return orderVOs;
    }

    @Override
    public OrderVO findOrderByOrderId(Long orderId) {
        // query order history operations
        OrderOperateHistory history = new OrderOperateHistory();
        history.setOrderId(orderId);
        List<OrderOperateHistory> operations = orderOperateHistoryService.find(history);

        // query order items
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(orderId);
        List<OrderItem> orderItems = orderItemService.find(orderItem);

        // query order itself
        Order order = findById(orderId);
        OrderVO orderVO = BeanUtil.copyProperties(order, OrderVO.class);
        orderVO.setOperations(operations);
        orderVO.setOrderItems(orderItems);
        return orderVO;
    }

    @Override
    public int getTotalOrderCountOfDate(String date) {
        return orderMapper.getTotalOrderCountOfDate(date);
    }

    @Override
    public BigDecimal getTotalSalesAmountOfDate(String date) {
        BigDecimal totalSalesAmount = orderMapper.getTotalSalesAmountOfDate(date);
        return totalSalesAmount == null ? new BigDecimal(0) : totalSalesAmount;
    }

    private void insertOrderOperateHistoryData(Order order, Date createTime) {
        OrderOperateHistory history = new OrderOperateHistory();
        history.setOrderId(order.getId());
        history.setOperateMan(order.getAppUserName());
        history.setCreateTime(createTime);
        history.setOrderStatus(order.getStatus());
        orderOperateHistoryService.insert(history);
    }

    private void insertOrderItemData(Order order, List<CartItem> cartItems) {
        List<OrderItem> orderItems = cartItems.stream()
                .map(item -> BeanUtil.copyProperties(item, OrderItem.class))
                .collect(Collectors.toList());

        orderItems.forEach(item -> {
            item.setOrderId(order.getId());
            item.setOrderSn(order.getOrderSn());
        });

        if (orderItems.size() > 0) {
            orderItemService.insertBatch(orderItems);
        }
    }

    private List<CartItem> removeCartItemsOfThisOrder(OrderDTO orderDTO) {
        List<CartItem> cartItems = orderDTO.getCartItems();
        cartItems.forEach(item -> {
            cartItemService.deleteById(item.getId());
        });
        return cartItems;
    }

    private Order insertOrderData(OrderDTO orderDTO) {
        String orderSn = generateUniqueOrderNumber();
        Date createTime = DateUtil.localDateTime2Date(LocalDateTime.now());
        Order order = BeanUtil.copyProperties(orderDTO, Order.class);
        order.setStatus(0);
        order.setOrderSn(orderSn);
        order.setCreateTime(createTime);
        insertSelective(order);
        return order;
    }

    @Override
    public int updateByIdSelective(Order entity) {
        int result;
        switch (entity.getStatus()) {
            case 1:
                result = payOrder(entity);
                break;
            case 2:
                result = deliverOrder(entity);
                break;
            case 3:
                result = receiveOrder(entity);
                break;
            case 4:
                result = closeOrder(entity);
                break;
            case 5:
                result = cancelOrder(entity);
                break;
            default:
                result = super.updateByIdSelective(entity);
                break;
        }
        return result;
    }

    private int payOrder(Order entity) {
        int result;
        // update order info
        Order order = findById(entity.getId());
        order.setStatus(1);
        Date paymentTime = DateUtil.localDateTime2Date(LocalDateTime.now());
        order.setPaymentTime(paymentTime);
        result = super.updateByIdSelective(order);

        // insert order history
        order.setAppUserName(order.getAppUserName());
        insertOrderOperateHistoryData(order, order.getPaymentTime());
        return result;
    }

    private int deliverOrder(Order entity) {
        int result;
        // update order info
        Order order = findById(entity.getId());
        order.setStatus(2);
        Date deliveryTime = DateUtil.localDateTime2Date(LocalDateTime.now());
        order.setDeliveryTime(deliveryTime);
        order.setDeliveryCompany(entity.getDeliveryCompany());
        order.setDeliverySn(entity.getDeliverySn());
        result = super.updateByIdSelective(order);

        // insert order history
        order.setAppUserName("系统管理员");
        insertOrderOperateHistoryData(order, order.getDeliveryTime());
        return result;
    }

    private int receiveOrder(Order entity) {
        int result;
        // update order info
        Order order = findById(entity.getId());
        order.setStatus(3);
        Date receiveTime = DateUtil.localDateTime2Date(LocalDateTime.now());
        order.setReceiveTime(receiveTime);
        result = super.updateByIdSelective(order);

        // insert order history
        order.setAppUserName(order.getAppUserName());
        insertOrderOperateHistoryData(order, order.getReceiveTime());
        return result;
    }

    private int closeOrder(Order entity) {
        int result;
        // update order info
        Order order = findById(entity.getId());
        order.setStatus(4);
        result = super.updateByIdSelective(order);

        // insert order history
        order.setAppUserName("系统管理员");
        insertOrderOperateHistoryData(order, DateUtil.localDateTime2Date(LocalDateTime.now()));
        return result;
    }

    private int cancelOrder(Order entity) {
        int result;
        // update order info
        Order order = findById(entity.getId());
        order.setStatus(5);
        result = super.updateByIdSelective(order);

        // insert order history
        order.setAppUserName(order.getAppUserName());
        insertOrderOperateHistoryData(order, DateUtil.localDateTime2Date(LocalDateTime.now()));
        return result;
    }
}
